package com.tlgen.orm.config;

import com.tlgen.orm.components.dataSource.DataSourceContextHolder;
import com.tlgen.orm.components.dataSource.DynamicDataSource;
import com.tlgen.orm.utils.log.ColorLogger;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Data
@Configuration
@ConfigurationProperties(prefix = "speed.orm")
public class SpeedOrmConfig {

    private Boolean fastMode;
    private Boolean openCache = true;

    // 新增堆外存储配置部分
    @NestedConfigurationProperty
    private OffHeapConfig offHeap = new OffHeapConfig();

    // ================= 新增 Caffeine 缓存配置 =================
    @NestedConfigurationProperty
    private CaffeineConfig caffeine = new CaffeineConfig();

    // ================= 新增 DataSource 多数据源配置 =================
    @NestedConfigurationProperty
    private List<DataSourceConfig> dynamicDatasource;

    // 内部类 - 堆外存储配置
    @Data
    public static class OffHeapConfig {
        // 基本启用开关
        private boolean enabled = true;

        // 熔断器配置
        @NestedConfigurationProperty
        private final CircuitBreaker circuitBreaker = new CircuitBreaker();

        // 迁移策略配置
        @NestedConfigurationProperty
        private final Migration migration = new Migration();

        // 内存配置
        @NestedConfigurationProperty
        private final Memory memory = new Memory();

        // 嵌套配置类 - 熔断器
        @Data
        public static class CircuitBreaker {
            /**
             * 错误率阈值百分比（达到此值将熔断）
             * 配置项：speed.orm.offheap.circuit-breaker.error-threshold
             */
            private int errorThreshold = 10;

            /**
             * 熔断恢复超时时间（毫秒）
             * 配置项：speed.orm.offheap.circuit-breaker.recovery-timeout
             */
            private long recoveryTimeout = 30000;
        }

        // 嵌套配置类 - 迁移策略
        @Data
        public static class Migration {
            /**
             * 大小阈值（字节），超过此值自动迁移到堆外
             * 配置项：speed.orm.offheap.migration.size-threshold
             */
            private long sizeThreshold = 102400; // 默认100KB

            /**
             * 访问频率阈值（次/分钟）
             * 配置项：speed.orm.offheap.migration.access-threshold
             */
            private int accessThreshold = 1000;
        }

        // 嵌套配置类 - 内存配置
        @Data
        public static class Memory {
            /**
             * 初始内存大小（支持单位：B, KB, MB, GB）
             * 配置项：speed.orm.offheap.memory.initial-size
             */
            @DataSizeUnit(DataUnit.MEGABYTES)
            private DataSize initialSize = DataSize.ofMegabytes(256);

            /**
             * 最大内存大小（支持单位：B, KB, MB, GB）
             * 配置项：speed.orm.offheap.memory.max-size
             */
            @DataSizeUnit(DataUnit.GIGABYTES)
            private DataSize maxSize = DataSize.ofGigabytes(4);

            /**
             * 内存池大小配置
             */
            @NestedConfigurationProperty
            private final Pools pools = new Pools();

            // 嵌套配置类 - 内存池
            @Data
            public static class Pools {
                /**
                 * 小对象池大小
                 * 配置项：speed.orm.offheap.memory.pools.small
                 */
                @DataSizeUnit(DataUnit.KILOBYTES)
                private DataSize small = DataSize.ofKilobytes(1);

                /**
                 * 中等对象池大小
                 * 配置项：speed.orm.offheap.memory.pools.medium
                 */
                @DataSizeUnit(DataUnit.KILOBYTES)
                private DataSize medium = DataSize.ofKilobytes(64);

                /**
                 * 大对象池大小
                 * 配置项：speed.orm.offheap.memory.pools.large
                 */
                @DataSizeUnit(DataUnit.MEGABYTES)
                private DataSize large = DataSize.ofMegabytes(1);
            }
        }
    }

    // ==================== 新增 CaffeineConfig 内部类 ====================
    @Data
    public static class CaffeineConfig {
        /**
         * 最大缓存条数
         * 默认值: 10000
         */
        private int maximumSize = 10000;

        /**
         * 写入后过期时间(毫秒)
         * 默认值: 30分钟(30 * 60 * 1000 = 1,800,000毫秒)
         */
        @DurationUnit(ChronoUnit.MILLIS)
        private Duration expireAfterWrite = Duration.ofMinutes(30);

        /**
         * 是否开启弱引用键 (weakKeys)
         */
        private boolean weakKeys = false;

        /**
         * 是否开启软引用值 (softValues)
         */
        private boolean softValues = false;

        /**
         * 是否开启统计功能
         */
        private boolean recordStats = true;
    }

    @Data
    public static class DataSourceConfig {
        private String driverClassName;
        private String dialect;
        private String name;
        private String type;
        private String url;
        private String username;
        private String password;
        private int poolSize;
        private boolean readOnly;
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<String, DataSource> targetDataSources = new HashMap<>();
        DataSource defaultDataSource = null;

        for (SpeedOrmConfig.DataSourceConfig config : this.getDynamicDatasource()) {
            DataSource ds = createDataSource(config);
            if (Objects.nonNull(ds)) {
                targetDataSources.put(config.getName(), ds);

                // 使用静态方法注册数据源
                DataSourceContextHolder.DataSourceInfo info = new DataSourceContextHolder.DataSourceInfo(
                        config.getName(),
                        config.getType(),
                        config.getDriverClassName(),
                        config.getUrl(),
                        config.isReadOnly()
                );
                DataSourceContextHolder.registerDataSource(config.getName(), info);

                if ("master_db".equals(config.getName())) {
                    defaultDataSource = ds;
                }
            }
        }

        // 如果没有指定master_db，则使用第一个数据源作为默认
        if (defaultDataSource == null && !targetDataSources.isEmpty()) {
            defaultDataSource = targetDataSources.values().iterator().next();
        }

        return new DynamicDataSource(defaultDataSource, targetDataSources);
    }

    private DataSource createDataSource(SpeedOrmConfig.DataSourceConfig config) {
        try {
            HikariDataSource ds = new HikariDataSource();
            ds.setJdbcUrl(config.getUrl());
            ds.setUsername(config.getUsername());
            ds.setPassword(config.getPassword());
            ds.setMaximumPoolSize(config.getPoolSize());
            ds.setReadOnly(config.isReadOnly());
            ds.setDriverClassName(config.getDriverClassName());
            return ds;
        } catch (Exception e) {
            System.err.println("Failed to create data source: " + config.getName());
            e.printStackTrace();
            return null;
        }
    }

    @Bean
    public Map<String, JdbcTemplate> jdbcTemplateMap(DataSource dynamicDataSource) {
        Map<String, JdbcTemplate> map = new HashMap<>();
        for (SpeedOrmConfig.DataSourceConfig config : this.getDynamicDatasource()) {
            JdbcTemplate template = new JdbcTemplate(dynamicDataSource);
            configureTemplate(template);
            map.put(config.getName(), template);
        }
        return map;
    }

    private void configureTemplate(JdbcTemplate template) {
        template.setFetchSize(100);
        template.setMaxRows(5000);
        template.setQueryTimeout(30);
    }

    @PostConstruct
    public void init() {
        // 初始化后打印数据源状态
        DataSourceContextHolder.DataSourceStats stats = DataSourceContextHolder.getStats();
        System.out.println("Data sources initialized. Active: " + stats.getActiveDataSourceCount());

        if (fastMode) {
            ColorLogger.printSuccessMessage(ColorLogger.ROCKET + " open fast api mode successfully");
        }
        if (openCache) {
            ColorLogger.printInfoMessage(ColorLogger.LIGHTNING + " default use cache query successfully");
        }
        if (offHeap.isEnabled()) {
            ColorLogger.printSuccessMessage(ColorLogger.FIRE + " off-heap storage enabled");
            log.info("Off-heap config: {}", offHeap);
        }
        // 新增日志
        if (caffeine != null) {
            log.info("Caffeine cache configured: maxSize={}, expireAfterWrite={}ms",
                    caffeine.getMaximumSize(),
                    caffeine.getExpireAfterWrite().toMillis());
        }
    }

    @PreDestroy
    public void destroy() {
        // 应用关闭时注销所有数据源
        for (SpeedOrmConfig.DataSourceConfig config : this.getDynamicDatasource()) {
            DataSourceContextHolder.deregisterDataSource(config.getName());
        }
        System.out.println("Data sources deregistered");
    }

}
